package cn.infinite.security.configuration;

import cn.infinite.security.annotation.AutoSignCheck;
import cn.infinite.security.core.SafeEndPoint;
import cn.infinite.security.core.SafePointScanner;
import cn.infinite.security.core.SecretKeyManager;
import cn.infinite.security.core.SignatureValidator;
import cn.infinite.security.core.impl.DefaultSecretKeyManager;
import cn.infinite.security.core.impl.DefaultSignatureValidator;
import cn.infinite.security.interceptor.SignatureValidateInterceptor;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.*;

@Configuration
@EnableConfigurationProperties({SimpleSignValidateKeyStore.class})
public class AutoSignValidateAutoConfiguration implements WebMvcConfigurer {


    @Resource
    private SignatureValidateInterceptor signatureValidateInterceptor;

    @Autowired(required = false)
    private RedisTemplate redisTemplate;

    /**
     * 默认密钥管理器，同时满足以下两个条件，此类会自动生效
     * 1.应用开启自动验签 {@link cn.infinite.security.annotation.EnableAutoCheckSign}
     * 2.当开发者没有自定义密钥管理器 {@link SecretKeyManager} 时
     */
    @Bean
    @ConditionalOnMissingBean(SecretKeyManager.class)
    @ConditionalOnBean({SimpleSignValidateKeyStore.class})
    public SecretKeyManager secretKeyManager(SimpleSignValidateKeyStore keyStore) {
        DefaultSecretKeyManager defaultSecretKeyManager = new DefaultSecretKeyManager(keyStore);
        return defaultSecretKeyManager;
    }

    /**
     * 安全端点扫描器
     *
     * @return
     */
    @Bean
    public SafePointScanner safePointScanner() {
        SafePointScanner safePointScanner = new SafePointScanner() {
            private ApplicationContext applicationContext;

            private List<SafeEndPoint> safeEndPointList = new ArrayList<>();

            @Override
            public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
                this.applicationContext = applicationContext;
                //获取所有Controller
                Map<String, Object> beansWithAnnotation = this.applicationContext.getBeansWithAnnotation(RequestMapping
                        .class);
                Collection<Object> values = beansWithAnnotation.values();
                Iterator<Object> iterator = values.iterator();

                while (iterator.hasNext()) {
                    //获取Controller中所有端点
                    Object next = iterator.next();
                    Class<?> aClass = next.getClass();
                    List<SafeEndPoint> safeEndPoints = this.analysisMethods(aClass);
                    this.safeEndPointList.addAll(safeEndPoints);
                }
            }

            private List<SafeEndPoint> analysisMethods(Class<?> mappingClass) {
                //获取mapping
                RequestMapping classAnnotation = mappingClass.getDeclaredAnnotation(RequestMapping.class);
                //获取自动验签注解
                AutoSignCheck classSignCheck = mappingClass.getDeclaredAnnotation(AutoSignCheck.class);
                String parentMapping = classAnnotation.value()[0];

                Method[] methods = mappingClass.getDeclaredMethods();
                List<SafeEndPoint> safeEndPoints = new ArrayList<>(methods.length);
                for (Method method : methods) {
                    String methodName = method.getName();
                    RequestMapping methodMapping = method.getAnnotation(RequestMapping.class);
                    if (methodMapping == null) {
                        //如果不是端点
                        continue;
                    }
                    AutoSignCheck methodSignCheck = method.getAnnotation(AutoSignCheck.class);
                    if (classSignCheck == null && methodSignCheck == null) {
                        //如果类和端点上都没有 签名验证的 需求
                        continue;
                    }
                    String[] includeMethodNames = classSignCheck.includeEndPointMethodName();
                    if (ArrayUtils.isNotEmpty(includeMethodNames) && !ArrayUtils.contains(includeMethodNames,
                            methodName)) {
                        //如果手动指明 包含端点列表，并且此方法不在范围之内
                        continue;
                    }
                    String[] excludeMethodNames = classSignCheck.excludeEndPointMethodName();
                    if (ArrayUtils.isNotEmpty(excludeMethodNames) && ArrayUtils.contains(excludeMethodNames,
                            methodName)) {
                        //如果指明排除此 端点
                        continue;
                    }
                    //优先使用 方法级别的 安全端点配置
                    SafeEndPoint safeEndPoint = new SafeEndPoint(parentMapping.concat(methodMapping.value()[0]),
                            methodSignCheck == null ? classSignCheck : methodSignCheck);

                    safeEndPoints.add(safeEndPoint);
                }
                return safeEndPoints;
            }

            @Override
            public Collection<SafeEndPoint> collect() {
                return this.safeEndPointList;
            }
        };

        return safePointScanner;
    }

    /**
     * 签名验证器
     *
     * @param secretKeyManager
     * @return
     */
    @Bean
    public SignatureValidator signatureValidator(SecretKeyManager secretKeyManager) {
        SignatureValidator signatureValidator = new DefaultSignatureValidator(secretKeyManager);
        return signatureValidator;
    }

    /**
     * 拦截器
     *
     * @return
     */
    @Bean
    public SignatureValidateInterceptor signatureValidateInterceptor(SignatureValidator signatureValidator) {
        SignatureValidateInterceptor interceptor = new SignatureValidateInterceptor(this.safePointScanner(),
                signatureValidator, redisTemplate);
        return interceptor;
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //装配到拦截器上
        registry.addInterceptor(this.signatureValidateInterceptor).addPathPatterns();
    }

}
